package com.thoughtworks.trains;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;


/**
 * 
 * @author water
 *
 */
public class TownsMap {
	
	private Town[] towns;
	
	private transient AtomicInteger size = new AtomicInteger(); 
	
	private static int DEFAULT_SIZE = 16;
	private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	
	public TownsMap(){
		towns = new Town[DEFAULT_SIZE];
	}
	
	public TownsMap(int size){
		if(size <= 0){
			size = DEFAULT_SIZE;
		}
		towns = new Town[size];
	}
	

	/**
	 * 添加城镇
	 * @param town
	 * @return
	 */
	public boolean addTown(Town town){
		//是否已经存在
		if(isExisted(town)){
			return true;
		}
		//容器是否满了
		if(isTownsFull()){
			resize();
		}
		towns[size.getAndIncrement()] = town;
		
		return true;
	}
	
	/**
	 * 添加城镇间的路径
	 * @param start
	 * @param end
	 * @param dis
	 * @return
	 */
	public boolean addRoute(Town start , Town end, int dis){
		if(dis <= 0){
			throw new IllegalArgumentException("distance should be more than 0");
		}
		if(! isExisted(start)){
			addTown(start);
		}
		if(! isExisted(end)){
			addTown(end);
		}
		start.addReachableTown(end);
		end.addRouteFromStartTown(start, dis);
		return true;
	}
	
	public IRouteService getRouteService(){
		return new RouteService();
	}

	/**
	 * 50%的扩容
	 */
	private void resize() {
		int minCapacity = towns.length+1;
		int oldCapacity = towns.length;
		int newCapacity = resize(minCapacity,oldCapacity);
		
		towns = Arrays.copyOf(towns, newCapacity);
		
	}
	
	
	private class RouteService implements IRouteService{
		public RouteService() {
		}
		
		@Override
		public int findRouteWithMax(String start,String end,int maxStops) {
			if(maxStops <= 0 ){
				throw new IllegalArgumentException("please give a number more than 0");
			}
			Town startTown = findTownByName(start);
			Town endTown = findTownByName(end);
			
			return startTown.search(endTown,maxStops);
		}

		@Override
		public String getDistance(String ... towns) {
			if(towns == null || towns.length < 2){
				throw new IllegalArgumentException("need more than 2 towns to caculate distance");
			}
			
			try{
				int distance = 0;
				String startTown = towns[0];
				Town town = findTownByName(startTown);
				boolean brokenFlag = false;
				for(int i=1; i< towns.length ; i++){
					String townName = towns[i];
					Town nextTown = findTownByName(townName);
					int dis = nextTown.getDis(town);
					if(dis > 0){
						distance+=dis;
						town = nextTown;
					}else{
						brokenFlag = true;
						break;
					}
				}
				
				//如果当distance大于0，路线未断过
				if(distance > 0 && !brokenFlag){
					return String.valueOf(distance);
				}
				
			}catch(Exception e){
				//log
			}
			
			return "NO SUCH ROUTE";
		}


		@Override
		public String findRouteCountWithExactly(String start, String end, int stops) {
			return null;
		}

		@Override
		public String findShortRoute(String start, String end) {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public void findRouteCountLessDis(String start, String end, int maxDis) {
			// TODO Auto-generated method stub
			
		}
	}
	
	
	
	/**
	 * 50%扩容
	 * @param minCapacity
	 * @param oldCapacity
	 * @return
	 */
	private int resize(int minCapacity,int oldCapacity){
		int newCapacity = oldCapacity + (oldCapacity >> 1);
		if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
		if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
		return newCapacity;
	}
	
	private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0)
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

	private boolean isTownsFull() {
		return towns.length == size.get();
	}

	
	/**
	 * 判断Town是否已经添加
	 * @param town
	 * @return 如果存在，返回true
	 */
	private boolean isExisted(Town town) {
		for(int i=0; i< size.get(); i++){
			Town existed = towns[i];
			if(existed.equals(town)){
				return true;
			}
		}
		return false;
	}
	
	private Town findTownByName(String name){
		for(int i=0; i<size.get(); i++){
			Town existed = towns[i];
			if(existed.getName().equalsIgnoreCase(name)){
				return existed;
			}
		}
		throw new IllegalArgumentException("don't have this town : "+name);
	}
	
}
